<?php

/**
 * \file
 * Classe permettant d'évaluer les accès d'un utilisateur.
 */

namespace pilar\Accesses /* \cond */ ; /* \endcond */
{

/**
 * Evaluateur d'accès d'un utilisateur..
 *
 * \since 02/02/2009
 * \author Matthieu OVIEDO <matthieu.oviedo@gmail.com>
 */
class Evaluator {

/**
 * Système d'utilisateurs.
 */
private $_system = null;


/**
 * Identifiant de l'utilisateur.
 */
public $_userId = null;


/**
 * Cache d'autorisations.
 */
private $_grantsCache = null;


/**
 * Cache d'autorisations par fonctions.
 */
private $_validatesCache = null;


/**
 * Signature des paramètres d'un accès.
 *
 * \param $params Paramètres.
 *
 * \return Signature des paramètres.
 */
private static function paramsSignature($params) {
 $signature = implode(',', $params);
 if ($signature == '') {
  $signature = 'EMPTY';
 }
 
 return $signature;
}


/**
 * Signature des paramètres, lorsque l'utilisateur à un accès générique.
 *
 * \param $params Paramètres.
 *
 * \return Signature des paramètres.
 */
private static function genericParamsSignature($params) {
 $signature = '';
 $length = sizeof($params);

 if ($length == 1) {
  $signature = '*';
 } else if ($length >= 2) { 
  for ($i = 1; $i < $length; $i++) {
   $signature += '*,';
  }
  $signature += '*';
 }

 return $signature;
}


/**
 * Permet de spécifier le système d'utilisateurs à utiliser pour l'évaluation
 * des accès.
 *
 * \param $system Système d'utilisateurs à utiliser.
 */
public function setSystem(System $system) {
 $this->_system = $system;
}


/**
 * Permet de spécifie l'identifiant de l'utilisateur concerné par l'évaluation
 * des accès.
 *
 * \param $userId Identifiant de l'utilisateur.
 */
public function setUserId($userId) {
 $this->_userId = $userId;

 // Réinitialisation des caches :
  $this->clearCache();
}


/**
 * Efface le cache d'accès.
 */
public function clearGrantsCache() {
 // Si le cache existe déjà il est effacé.
  if($this->_grantsCache != null) unset($this->_grantsCache);

 // Un nouveau cache vide est ensuite créé.
  $this->_grantsCache = array();
}


/**
 * Efface le cache des fonctions d'accès.
 */
public function clearValidatesCache() {
 // Si le cache existe déjà il est effacé.
  if($this->_validatesCache != null) unset($this->_validatesCache);

 // Un nouveau cache vide est ensuite créé.
  $this->_validatesCache = array();
}


/**
 * Efface tous les caches.
 */
public function clearCache() {
 $this->clearValidatesCache();
 $this->clearGrantsCache();
}


/**
 * Détermine si l'utilisateur détient ou pas une autorisation pour un accès
 * donné en fonction de paramètres éventuels. Un cache est géré en interne.
 * Dans le cas où l'accès n'est pas accordé par les paramètres données,
 * on vérifie si l'utilisateur n'a pas un accès générique (avec des
 * paramètres *).
 *
 * \param $access Nom de l'accès.
 * \param $params Paramètres d'accès (l'ordre est important).
 *
 * \return \c TRUE si l'utilisateur a l'accès, \c FALSE sinon.
 */
public function granted($access, $params = null) {
 if($params == null) $params = array();

 // Création de la chaîne de paramètre $allParams :
  $genericParamsSignature = self::genericParamsSignature($params);

 // Calcul de la signature associée aux paramètres :
  $signature = self::paramsSignature($params);
  
 // Si besoin on évalue et on met en cache l'accès demandé :
  if (!isset($this->_grantsCache[$access][$signature])) {
   if (!isset($this->_grantsCache[$access][$genericParamsSignature]) || 
        !$this->_grantsCache[$access][$genericParamsSignature]) {
    if (!isset($this->_grantsCache[$access])) {
     $this->_grantsCache[$access] = array();
    }
    
    $this->addGrantToCache($access, $signature);

    if (!$this->_grantsCache[$access][$signature] &&
         (!isset($this->_grantsCache[$access][$genericParamsSignature]) ||
           !$this->_grantsCache[$access][$genericParamsSignature])) {
     $this->addGrantToCache($access, $genericParamsSignature);

     return $this->_grantsCache[$access][$genericParamsSignature];
    }
   } else {
   	
    return $this->_grantsCache[$access][$genericParamsSignature];
   }
  }

 // Retour du status de l'accès demandé :
  return $this->_grantsCache[$access][$signature];
}


/**
 * Fonction permettant de tester si l'utilisateur a une permission quelconque
 * sur un accès.
 * 
 * \param $access L'identifiant numérique de l'accès en question.
 * \return \c TRUE s'il a une permission, \c FALSE sinon.
 * \since 21/06/2009
 */
public function hasPermissionOnAccess($access) {
 if (isset($this->grantsCache[$access])) {
  if (in_array(true, $this->grantsCache[$access])) {
   return true;
  }
 } else {
  return $this->_system->hasPermissionOnAccess($this->_userId, $access);
 }
}


/**
 * Vérifie un acces.
 *
 * \since 02/06/2009
 */
private function addGrantToCache($access, $signature) {
 $this->_grantsCache[$access][$signature] = (
  $this->_system->userGranted(
   $this->_userId,
   $access,
   $signature
  )
 );
}


public function setGrantsCache($grantsCache) {
	$this->_grantsCache = $grantsCache;
}


/**
 * Evalue avec cache un accès défini par une fonction.
 *
 * \param $name Nom local de la fonction.
 * \param $namespace Espace de nom où se trouve la fonction.
 * \param $params Paramètres à passer à la fonction.
 * \return \c TRUE si l'utilisateur a l'accès, \c FALSE sinon.
 * \since 11/05/2009
 */
public function validates($id, $name, $namespace, $params = null) {
 if($params == null) $params = array();

 // Calcul de la signature associée aux paramètres :
  $signature = self::paramsSignature($params);

 // Si besoin on évalue et on met en cache l'accès demandé :
  if (!isset($this->_validatesCache[$id][$signature])) {
   if (!isset($this->_validatesCache[$id])) {
    $this->_validatesCache[$id] = array();
   }
   $funcName = $namespace.'\\AccessFunctions::'.$name;
   eval('$validation = '.$funcName.'($params);');
   $this->_validatesCache[$id][$signature] = $validation;
  }

 // Retour du status de l'accès demandé :
  return $this->_validatesCache[$id][$signature];
}


} // Class.

} // Namespace.

?>
